package com.dhms.uikit

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint

import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.annotation.ColorInt
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap

open class StopwatchView : View, Animator.AnimatorListener {
    companion object {
        const val DEFAULT_RING_WIDTH: Float = 24f
        const val DEFAULT_DURATION: Int = 20

        @ColorInt
        const val DEFAULT_INNER_CYCLE_COLOR: Int = 0x006CB8

        @ColorInt
        const val DEFAULT_RING_COLOR: Int = 0x00A0E9
        private const val ROUND_MODE_OUTER: Int = 0
        private const val ROUND_MODE_INNER: Int = 1
        const val DEFAULT_ROUND_MODE: Int = ROUND_MODE_OUTER
    }

    private lateinit var _ringPaint: Paint
    private var _stopwatchListener: StopwatchListener? = null
    private var _ringWidth: Float = DEFAULT_RING_WIDTH
    private var _roundMode: Int = DEFAULT_ROUND_MODE
    private var _timeDuration = DEFAULT_DURATION
    private var _currentProgressAngle = 0f
    private lateinit var _innerCyclePaint: Paint
    private var _iconInCenter: Bitmap? = null

    protected var centerX: Float = _ringWidth / 2
    protected var centerY: Float = _ringWidth / 2

    private lateinit var progressAnimator: ValueAnimator

    /**
     * The duration of audio record
     */
    var timeDuration: Int
        get() = _timeDuration
        set(value) {
            if (value < 0) {
                throw IllegalArgumentException("wrong time duration $value")
            }
            _timeDuration = value
            progressAnimator.duration = _timeDuration.toLong() * 1000
        }

    fun getProcess(): Float {
        return _currentProgressAngle / 360
    }

    constructor(context: Context) : super(context) {
        init(null, 0)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init(attrs, 0)
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
        context,
        attrs,
        defStyle
    ) {
        init(attrs, defStyle)
    }

    private fun init(attrs: AttributeSet?, defStyle: Int) {
        // Load attributes
        val a = context.obtainStyledAttributes(
            attrs, R.styleable.StopwatchView, defStyle, 0
        )

        val duration = a.getInt(R.styleable.StopwatchView_duration, DEFAULT_DURATION)
        if (duration < 1) {
            throw IllegalArgumentException("wrong record duration $duration")
        }
        _timeDuration = duration

        val ringWidth = a.getDimension(R.styleable.StopwatchView_ring_width, DEFAULT_RING_WIDTH)
        if (ringWidth < 1) {
            throw IllegalArgumentException("wrong ringWidth $ringWidth")
        }
        _ringWidth = ringWidth
        _roundMode = a.getInt(R.styleable.StopwatchView_surrounded, DEFAULT_ROUND_MODE)
        val innerCycleColor =
            a.getColor(R.styleable.StopwatchView_cycle_color, DEFAULT_INNER_CYCLE_COLOR)
        val ringColor = a.getColor(R.styleable.StopwatchView_ring_color, DEFAULT_RING_COLOR)
        val iconResource = a.getResourceId(R.styleable.StopwatchView_icon_in_center, 0)
        a.recycle()
        // fill the inner cycle paint
        _innerCyclePaint = Paint()
        _innerCyclePaint.style = Paint.Style.FILL
        _innerCyclePaint.color = innerCycleColor
        // fill the ring paint
        _ringPaint = Paint()
        _ringPaint.style = Paint.Style.FILL_AND_STROKE
        _ringPaint.color = ringColor
        // init the microphone icon
        if (iconResource != 0) {
            _iconInCenter =
                ResourcesCompat.getDrawable(
                    context.resources,
                    iconResource,
                    context.theme
                )?.toBitmap()
        }
        // init audio record progress animator
        progressAnimator = ValueAnimator()
        progressAnimator.duration = _timeDuration.toLong() * 1000
        progressAnimator.setFloatValues(0f, 360f)
        progressAnimator.interpolator = LinearInterpolator()
        progressAnimator.addListener(this)
        progressAnimator.addUpdateListener { animation ->
            _currentProgressAngle = animation?.animatedValue as Float
            postInvalidate()
        }
    }

    override fun onDraw(canvas: Canvas) {
        val contentWidth = (width - paddingLeft - paddingRight).toFloat()
        val contentHeight = (height - paddingTop - paddingBottom).toFloat()
        centerX = contentWidth / 2 + paddingLeft
        centerY = contentHeight / 2 + paddingTop
        val radios = contentWidth.coerceAtMost(contentHeight) / 2 - _ringWidth
        if (_roundMode == ROUND_MODE_INNER) {
            canvas.drawCircle(
                centerX,
                centerY,
                contentWidth.coerceAtMost(contentHeight) / 2,
                _innerCyclePaint
            )
        }

        canvas.drawArc(
            paddingLeft.toFloat(),
            paddingTop.toFloat(),
            (width - paddingRight).toFloat(),
            (height - paddingBottom).toFloat(),
            -90f,
            _currentProgressAngle,
            true,
            _ringPaint
        )

        canvas.drawCircle(
            centerX,
            centerY,
            radios,
            _innerCyclePaint
        )

        drawIconInCenter(canvas)
    }

    open fun drawIconInCenter(canvas: Canvas) {
        if (_iconInCenter != null) {
            val widthOfIcon = _iconInCenter!!.width
            val heightOfIcon = _iconInCenter!!.height / 2
            canvas.drawBitmap(
                _iconInCenter!!,
                centerX - widthOfIcon / 2,
                centerY - heightOfIcon,
                Paint()
            )
        }
    }

    /**
     * start audio record
     */
    fun start() {
        if (progressAnimator.isStarted) {
            progressAnimator.cancel()
        }
        progressAnimator.start()
    }

    /**
     * stop started audio record
     */
    fun stop() {
        progressAnimator.cancel()
    }

    // region audio record progress animator listener
    override fun onAnimationStart(p0: Animator?) {
        _stopwatchListener?.apply { onStarted() }
    }

    override fun onAnimationEnd(p0: Animator?) {
        _stopwatchListener?.apply { onStop() }
    }

    override fun onAnimationCancel(p0: Animator?) {
        _currentProgressAngle = 0f
    }

    override fun onAnimationRepeat(p0: Animator?) {
        // do nothing
    }

    // endregion
    interface StopwatchListener {
        fun onStarted()
        fun onStop()
    }
}
